﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using PropertyManagment.config.cache;
using PropertyManagment.config.jwt;
using PropertyManagment.service;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

namespace PropertyManagment.common.Filter {

    public class AuthorizeFilter : IAuthorizationFilter {

        private readonly ILogger logger;
        private readonly ICacheHelper cache;
        private readonly IConfiguration configuration;
        private readonly SysUserService sysUserService;

        public AuthorizeFilter(ICacheHelper cache, ILogger<AuthorizeFilter> logger, IConfiguration configuration, SysUserService sysUserService) {
            this.logger = logger;
            this.cache = cache;
            this.configuration = configuration;
            this.sysUserService = sysUserService;
        }

        public void OnAuthorization(AuthorizationFilterContext context) {
            logger.LogInformation("登录认证过滤器");
            //Debug.WriteLine(JsonConvert.SerializeObject(context.ActionDescriptor.EndpointMetadata));
            //登录用户名
            //Debug.WriteLine(context.HttpContext.User.Identity.Name);
            //请求的地址
            //Debug.WriteLine(context.HttpContext.Request.Path.Value);
            //打印头部信息
            //Debug.WriteLine(context.HttpContext.Request.Headers["Authorization"]);
            //Debug.WriteLine(JsonConvert.SerializeObject(context.HttpContext.Request.Headers));
            //直接在页面打印信息
            //context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");

            //修改401返回的返回值 正常的401报错
            //context.Result = new StatusCodeResult(401);
            //自定义的401报错:
            //context.Result = new JsonResult(new { StatusCodeResult = StatusCodes.Status401Unauthorized, Title = "401", Time = DateTime.Now, test = "测试" });

            //如果controller或方法上有Authorize,且token过期或没带token的请求,会进入这里判断
            if (context.HttpContext.Request.Path.Value == "/Error/401") {
                updateToken(context);
            }

            var actionDescriptor = context.ActionDescriptor;
            if (actionDescriptor.EndpointMetadata.Any(p => p is AllowAnonymousAttribute)) {
                logger.LogInformation("跳过过滤器");
                return;
            } else {
                //判断是否登录
                if (context.HttpContext.User.Identity.Name != null) {
                    logger.LogInformation("检查令牌是否可用");

                    //判断该token是否已经登出
                    List<string> authorizations = new List<string>();
                    if (cache.IsExist(context.HttpContext.User.Identity.Name)) {
                        authorizations = cache.Get<List<string>>(context.HttpContext.User.Identity.Name);
                        //Debug.WriteLine(JsonConvert.SerializeObject(authorizations));
                        if (authorizations.Contains(context.HttpContext.Request.Headers["Authorization"])) {
                            context.Result = new JsonResult(new { code = StatusCodes.Status401Unauthorized, msg = "请先登录" });
                        }
                    }
                }
                //如果controller或方法上没有Authorize, 且token过期或没带token的请求都不会出现401状态码, 也获取不了name, 并执行下面代码

            }
        }

        private void updateToken(AuthorizationFilterContext context) {
            //判断缓存中的tokan是否过期
            if (cache.IsExist(context.HttpContext.Request.Headers["Authorization"])) {
                logger.LogInformation("还没过期，更新Token");
                string username = cache.Get<string>(context.HttpContext.Request.Headers["Authorization"]);
                if (username== "正在更新token") {
                    context.Result = new JsonResult(new { code = StatusCodes.Status401Unauthorized, msg = "正在更新Token" });
                    return;
                }
                //保留旧的token30秒，在这30秒用旧的token来的请求都是返回“正在更新token”
                cache.Set(context.HttpContext.Request.Headers["Authorization"], "正在更新token", 30);
                var jwtConfig = configuration.GetSection("JwtConfig").Get<JwtConfig>();
                //把旧的token放进登出名单
                List<string> authorizations = new List<string>();
                if (cache.IsExist(username)) {
                    authorizations = cache.Get<List<string>>(username);
                }
                authorizations.Add(context.HttpContext.Request.Headers["Authorization"]);
                cache.Set(username, authorizations, jwtConfig.expires);
                //没有过期则重新获取token，重新计时
                var user = sysUserService.loadUserByUsername(username);
                if (user != null) {
                    string token = JwtToken.getToken(jwtConfig, username, user.authorities);
                    //把token存进缓存，过期时间为token的4倍
                    token = "Bearer " + token;
                    cache.Set(token, username, jwtConfig.expires * 4);
                    context.Result = new JsonResult(new { code = StatusCodes.Status401Unauthorized, msg = "更新Token", data = token });
                    return;
                } else {
                    context.Result = new JsonResult(new { code = StatusCodes.Status401Unauthorized, msg = "请先登录" });
                }
            } else {
                context.Result = new JsonResult(new { code = StatusCodes.Status401Unauthorized, msg = "请先登录" });
            }
        }

    }
}
